﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.Security.Cryptography.Xml;

namespace Sistema.Util
{
    public class AssinaXML
    {
        public XmlDocument AssinarXML(String Xml, String TagAssinatura, X509Certificate2 certificadoDigital)
        {
            XmlDocument DocumentoXml = new XmlDocument();

            DocumentoXml.LoadXml(Xml);

            // Verifica se a tag a ser assinada existe e é única
            int qtdeRefUri = DocumentoXml.GetElementsByTagName(TagAssinatura).Count;

            if (qtdeRefUri == 0)
            {
                throw new NotImplementedException();
            }
            // Exsiste mais de uma tag a ser assinada
            else
            {
                if (qtdeRefUri > 1)
                {
                    throw new NotImplementedException();
                }
                try
                {
                    // Create a SignedXml object.
                    SignedXml signedXml = new SignedXml(DocumentoXml);

                    // Add the key to the SignedXml document 
                    signedXml.SigningKey = certificadoDigital.PrivateKey;

                    // Create a reference to be signed
                    Reference reference = new Reference();
                    // pega o uri que deve ser assinada
                    XmlAttributeCollection _Uri = DocumentoXml.GetElementsByTagName(TagAssinatura).Item(0).Attributes;
                    foreach (XmlAttribute _atributo in _Uri)
                    {
                        if (_atributo.Name == "Id")
                        {
                            reference.Uri = "#" + _atributo.InnerText;
                        }
                    }

                    // Add an enveloped transformation to the reference.
                    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                    reference.AddTransform(env);

                    XmlDsigC14NTransform c14 = new XmlDsigC14NTransform();
                    reference.AddTransform(c14);

                    // Add the reference to the SignedXml object.
                    signedXml.AddReference(reference);

                    // Create a new KeyInfo object
                    KeyInfo keyInfo = new KeyInfo();

                    // Load the certificate into a KeyInfoX509Data object
                    // and add it to the KeyInfo object.
                    keyInfo.AddClause(new KeyInfoX509Data(certificadoDigital));

                    // Add the KeyInfo object to the SignedXml object.
                    signedXml.KeyInfo = keyInfo;

                    signedXml.ComputeSignature();

                    // Get the XML representation of the signature and save
                    // it to an XmlElement object.
                    XmlElement xmlDigitalSignature = signedXml.GetXml();

                    // Append the element to the XML document.
                    DocumentoXml.DocumentElement.AppendChild(DocumentoXml.ImportNode(xmlDigitalSignature, true));
                    XmlDocument retorno = new XmlDocument();
                    retorno.PreserveWhitespace = false;
                    retorno = DocumentoXml;
                    return retorno;
                }
                catch (Exception ex)
                {
                    throw new NotImplementedException();
                }
            }
        }
    }
}